package com.yryp.sign.mq.utils;

import java.io.ByteArrayOutputStream;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;

import org.apache.commons.lang3.StringUtils;

import sun.misc.BASE64Encoder;

/**
 * @ClassName: RSAUtil
 * @Description: RSA加密解密工具类
 * @author haomt
 * @date 2018年3月5日
 */
@SuppressWarnings("restriction")
public class MqrsaUtil {

	/**
	 * RSA最大加密明文大小
	 */
	private static final int MAX_ENCRYPT_BLOCK = 117;

	/**
	 * RSA最大解密密文大小
	 */
	private static final int MAX_DECRYPT_BLOCK = 128;

	private static final String PRIVATE_KEY = "MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJ"
			+ "eAgEAAoGBAJ2msiGRbzJDoOVJIbDEauZKuiAfpkqzkzOzCCi/6D0k6jR0qm/xFEXQH14LpWwCOkD"
			+ "hhPO8RC2CBx049kWSQd2t76Nk9tsKY4+nA/JZUIj7x/XauNd+D3oWdJILBEXB3SxP4oZ8eQJxYpa"
			+ "UN6nDiCi5W+Q4GrjpYDbNKgEHzSZZAgMBAAECgYBctOktekOkkEZubuoD9A1U7X60Y0g7x4v5q/9R"
			+ "T0D3q9yaCj0r5N3iC/hWKo0Vjd3Jx5SSbBS/miYq1hNkaBSYn9aegxmIunIbK6o6IsyvRCwI45VJsf"
			+ "GINyJsTqjYYUo4qgAVuhcM63pPc9uXsVDV9vGQLY7gkqc2OsfjQd5dzQJBAP4v2HENJ0BFDxFFjoF9y"
			+ "5ryCughpXUY5Kz7iiF5Yhb00vnEaOttyCW8O21tM+CCrfxAX/2RCaZno/p1dVHJRwMCQQCexpKUJw4Ay"
			+ "7D29LHcSBZ/IyNJRpDB2+z9lD4nxrgaubs6LH3vwzHvgiyV6++G8BhRAjNftaa46YP2rJ08YMBzAkEAx"
			+ "4Xg/OSZQd6zdBhIQybuUmLZ4tq+WMtAfPQ5ugrgzypADSR6Qwr6h3xYnY2RohKR5abWcmCN1ZwW4Dug6q"
			+ "D25wJBAIYN+FI4Cz2mvRo1DTqEbuIXI8LJXo0fB6AuGrBwup5t9GMwj3/w2Wd0C/rkwk62xoEXD5Mehs6W8"
			+ "oFBylvhAHsCQQD8CRmctR/XOq7I+kwysmLAx9RC6HYp8xwECp6C7v9wQe7sFZmkNUjG43R1PMUH2EPl/vT+"
			+ "p/W0Xksou/AFFh9L";

	private static final String PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCd"
			+ "prIhkW8yQ6DlSSGwxGrmSrogH6ZKs5Mzswgov+g9JOo0dKpv8RRF0B9eC6VsAjpA4YTzvEQtggcdO"
			+ "PZFkkHdre+jZPbbCmOPpwPyWVCI+8f12rjXfg96FnSSCwRFwd0sT+KGfHkCcWKWlDepw4gouVvkOB"
			+ "q46WA2zSoBB80mWQIDAQAB";

	public static String decryptRSA(String source) throws Exception {
		if (StringUtils.isBlank(source))
			return "";
			byte[] res = decrypt(loadPrivateKeyByStr(PRIVATE_KEY), Base64Code.decode(source));
			return new String(res);

	}

	public static RSAPrivateKey loadPrivateKeyByStr(String privateKeyStr) throws Exception {
		try {
			byte[] buffer = Base64Code.decode(privateKeyStr);
			PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(buffer);
			KeyFactory keyFactory = KeyFactory.getInstance("RSA");
			return (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
		} catch (NoSuchAlgorithmException e) {
			throw new Exception("无此算法");
		} catch (InvalidKeySpecException e) {
			throw new Exception("私钥非法");
		} catch (NullPointerException e) {
			throw new Exception("私钥数据为空");
		}
	}

	public static byte[] decrypt(RSAPrivateKey privateKey, byte[] cipherData) throws Exception {
		if (privateKey == null) {
			throw new Exception("解密私钥为空, 请设置");
		}
		Cipher cipher = null;
		int inputLen = cipherData.length;
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		int offSet = 0;
		byte[] cache;
		int i = 0;
		try {
			cipher = Cipher.getInstance("RSA");
			cipher.init(Cipher.DECRYPT_MODE, privateKey);
			while (inputLen - offSet > 0) {
				if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
					cache = cipher.doFinal(cipherData, offSet, MAX_DECRYPT_BLOCK);
				} else {
					cache = cipher.doFinal(cipherData, offSet, inputLen - offSet);
				}
				out.write(cache, 0, cache.length);
				i++;
				offSet = i * MAX_DECRYPT_BLOCK;
			}
			byte[] decryptedData = out.toByteArray();
			out.close();
			return decryptedData;
		} catch (NoSuchAlgorithmException e) {
			throw new Exception("无此解密算法");
		} catch (NoSuchPaddingException e) {
			e.printStackTrace();
			return null;
		} catch (InvalidKeyException e) {
			throw new Exception("解密私钥非法,请检查");
		} catch (IllegalBlockSizeException e) {
			throw new Exception("密文长度非法");
		} catch (BadPaddingException e) {
			throw new Exception("密文数据已损坏");
		}
	}

	public static String encryptRSA(String source) throws Exception {
		if (StringUtils.isBlank(source))
			return "";

		return encryptWithBase64(source);
	}

	public static String encryptWithBase64(String source) throws Exception {
		if (StringUtils.isBlank(source))
			return "";
		try {
			byte[] cipherData = encrypt(loadPublicKeyByStr(PUBLIC_KEY), source.getBytes("UTF-8"));
			return new BASE64Encoder().encodeBuffer(cipherData);
		} catch (Exception ex) {
			throw new Exception("RSA加密错误");
		}
	}

	public static RSAPublicKey loadPublicKeyByStr(String publicKeyStr) throws Exception {
		try {
			byte[] buffer = Base64Code.decode(publicKeyStr);
			KeyFactory keyFactory = KeyFactory.getInstance("RSA");
			X509EncodedKeySpec keySpec = new X509EncodedKeySpec(buffer);
			return (RSAPublicKey) keyFactory.generatePublic(keySpec);
		} catch (NoSuchAlgorithmException e) {
			throw new Exception("无此算法");
		} catch (InvalidKeySpecException e) {
			throw new Exception("公钥非法");
		} catch (NullPointerException e) {
			throw new Exception("公钥数据为空");
		}
	}

	public static byte[] encrypt(RSAPublicKey publicKey, byte[] plainTextData) throws Exception {
		if (publicKey == null) {
			throw new Exception("加密公钥为空, 请设置");
		}
		Cipher cipher = null;
		int offSet = 0;
		int i = 0;
		byte[] cache;
		int inputLen = plainTextData.length;
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		try {
			cipher = Cipher.getInstance("RSA");
			cipher.init(Cipher.ENCRYPT_MODE, publicKey);
			while (inputLen - offSet > 0) {
				if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
					cache = cipher.doFinal(plainTextData, offSet, MAX_ENCRYPT_BLOCK);
				} else {
					cache = cipher.doFinal(plainTextData, offSet, inputLen - offSet);
				}
				out.write(cache, 0, cache.length);
				i++;
				offSet = i * MAX_ENCRYPT_BLOCK;
			}
			byte[] encryptedData = out.toByteArray();
			out.close();
			return encryptedData;
		} catch (NoSuchAlgorithmException e) {
			throw new Exception("无此加密算法");
		} catch (NoSuchPaddingException e) {
			e.printStackTrace();
			return null;
		} catch (InvalidKeyException e) {
			throw new Exception("加密公钥非法,请检查");
		} catch (IllegalBlockSizeException e) {
			throw new Exception("明文长度非法");
		} catch (BadPaddingException e) {
			throw new Exception("明文数据已损坏");
		}
	}

}
